iT邦幫忙

2026 iThome 鐵人賽

DAY 9
0

https://ithelp.ithome.com.tw/upload/images/20260809/20161290pNkPQfbs8A.png

從使用者輸入到 goal output 的生命周期

今天要解決的問題

  • Process 保存輸入、計畫與事件
  • 每步後重新檢查 blackboard
  • 失敗點可被解釋

內容

前面幾天談的都是「宣告」:action 有哪些、goal 長什麼樣、條件怎麼寫。但宣告本身不會動。真正把一次使用者請求跑起來的,是 AgentProcess。

AgentProcess 是一次 agent 任務的容器。它包含使用者輸入、初始 facts、目標、候選 actions、目前 plan、Blackboard、事件與終止狀態。當你要除錯 agent 為什麼走某條路時,AgentProcess 是最重要的觀察對象——因為所有線索都在裡面。

Embabel 的流程不是一次排完就盲目跑到底。每個 action 執行後,Blackboard 狀態會更新,planner 可以根據新狀態重新規劃。這就是官方文件說的 OODA loop:Observe 觀察 blackboard 目前狀態與 action 結果、Orient 理解上一輪之後發生了什麼變化、Decide 依新資訊重新規劃、Act 執行計畫中的下一個 action。這個概念原本來自軍事決策理論,用在這裡的意思很單純:不要假設計畫一定會照著走。

這種設計讓錯誤恢復變得具體。如果 fetchActivity 找不到客戶,流程不會假裝摘要;如果 reviewOffer 擋下草稿,系統可以改走重新生成或人工審核。每個停點都有條件可解釋。

觀念圖解

AgentProcess 是一次任務的容器,可以把它想成「這次 agent 執行的案件資料夾」。

AgentProcess 執行迴圈

它會保存使用者輸入、目前 blackboard、已選 goal、執行過的 action、事件與結束狀態。每跑完一步,系統就重新看狀態,判斷是否已經達標或還要繼續。

AgentInvocation 程式化呼叫

實務上不會只靠 shell 測試 agent,而會從 REST controller 或 service 呼叫。AgentInvocation 的價值,就是讓 agent 執行變成一般後端流程的一部分——指定目標型別、同步拿結果,跟呼叫一個 service 方法沒兩樣。

如果你的系統需要更彈性的入口,Embabel 還提供 Autonomy API,讓 LLM 自己挑要跑哪個 agent:

方式 誰選 agent 適合場景
AgentInvocation 開發者指定 goal 型別 REST 端點、確定性流程
Autonomy(Closed mode) LLM 從已註冊 agent 中挑 多 agent 系統的統一入口
Autonomy(Open mode) LLM 挑 goal,可跨 agent 組合 action 使用者意圖不確定的探索式呼叫

大多數生產場景用 AgentInvocation 就夠了:REST 端點進來、指定 goal 型別、同步拿結果。Autonomy 要等到你真的有「使用者意圖不確定、需要 LLM 幫忙挑 agent」的需求時再說。

一次查詢的執行軌跡

觀念講完了,來看一次真實執行長什麼樣。客服輸入「客戶 4711 的近一年活動」後,Blackboard 會逐步累積物件:

步驟 Blackboard 內容 Planner 決策
開始 CustomerQuery 推導出 fetchActivity → summarize → proposeOffer → reviewOffer
fetchActivity 完成 + TravellerActivity 照計畫執行 summarize
summarize 完成 + ActivitySummary(標記 high spender) 照計畫執行 proposeOffer
proposeOffer 完成 + OfferDraft(升等方案) 照計畫執行 reviewOffer
reviewOffer 未通過 (沒有 ReviewedOffer) Replanning:改走 escalateToHuman
escalateToHuman 完成 + EscalationTicket Goal 達成(安全失敗終點),process 終止

這張表最值得看的是倒數第二列。reviewOffer 沒通過時,planner 不是無限重試,而是改走 escalateToHuman——因為那條路也標了 @AchievesGoal,planner 知道走那邊也能收工。這就是為什麼一條流程通常至少要設計兩個 goal:一個正常終點,一個安全失敗終點。

那它會不會一直重試下去

看到 replanning 這個機制,多數人第一個疑問都是這個:如果只有一個 goal,而那條路一直失敗,不就無限迴圈了嗎?

Embabel 對此有三層防護,責任由上而下遞減:

  • 第一層:多 Goal 設計(開發者責任)——如上表,設計「正常終點」與「安全失敗終點」兩個 @AchievesGoal,讓 planner 在主路徑走不通時有替代出口可收斂。
  • 第二層:StuckHandler 介面(agent 自救)——當 planner 找不到任何可執行的 action,框架會呼叫 StuckHandler.handleStuck()。agent 可以自行補資料進 blackboard 後請求 REPLAN,或乾脆回報失敗。
  • 第三層:EarlyTerminationPolicy(平台硬停機)——透過 ProcessOptions 設定最大 action 數或成本上限,超過就強制終止。這是最後的保險絲。

好的設計應該在第一層就解決問題。如果你的 agent 經常觸發 StuckHandler,或常被 EarlyTerminationPolicy 中止,那代表 GOAP 模型本身需要重新設計——保險絲一直燒,不是換更粗的保險絲,是去看電路哪裡有問題。

程式碼補充

執行視角要補上的重點是:程式碼宣告的是能力,AgentProcess 負責把一次使用者任務跑起來,保存輸入、目前狀態、執行事件與最後結果。也就是說,action 是零件,AgentProcess 是一次流程實例。

多個 agent 怎麼被串起來

前面那張表提到 Autonomy 可以讓 LLM 自己挑 agent,但實務上還有一種更常見的情況:使用者一句話裡包含好幾個問題。像「客戶流失風險 + 上月營收 + 客訴摘要」這種複合查詢,通常不是靠單一 agent 一口氣完成,而是:

  1. 先拆成多個子查詢
  2. 逐個選 agent 執行
  3. 再做融合

值得注意的是,這段編排通常不寫在 @Action 裡,而是寫在 service 或 controller 層

public record SubQuerySet(List<String> items) {}
public record PartialInsight(String topic, String summary) {}
public record FusedInsight(List<PartialInsight> insights) {}

@Service
public class InsightOrchestrator {

    private final Autonomy autonomy;
    private final AgentPlatform agentPlatform;

    public InsightOrchestrator(Autonomy autonomy, AgentPlatform agentPlatform) {
        this.autonomy = autonomy;
        this.agentPlatform = agentPlatform;
    }

    /**
     * 將複合查詢拆解後,逐一交給最合適的 agent,再融合成單一結果。
     */
    public FusedInsight analyze(String userIntent) {
        SubQuerySet queries = new SubQuerySet(List.of(
            "分析流失風險",
            "分析上月營收",
            "整理近期客訴"
        ));

        List<PartialInsight> results = new ArrayList<>();
        for (String item : queries.items()) {
            AgentProcessExecution execution =
                autonomy.chooseAndRunAgent(item, ProcessOptions.DEFAULT);
            results.add((PartialInsight) execution.getOutput());
        }

        return new FusedInsight(results);
    }
}

這段有三個地方值得留意:

  • autonomy.chooseAndRunAgent(...) 就是上表 Closed mode 的實際樣子——讓 LLM 從已註冊 agent 中挑一個最適合的
  • 融合用的輸出型別最好獨立,例如這裡的 FusedInsight
  • 不要讓多個 agent 都吐同一個模糊型別,否則 orchestration 層很容易搞不清楚拿到的是誰的結果

換句話說,多 agent 協作不是把更多東西塞回單一 @Action,而是讓每個 agent 各自完整,再由上層決定怎麼組合。

今日實作 / 思考任務

寫一份 AgentProcess 執行軌跡表:每列包含 action、輸入物件、輸出物件、Blackboard 新增內容與可能的 replanning。

接著再想一題:如果把這條流程拆成多個 agent,哪個輸出型別應該獨立成融合專用的 record?


如果你也想進一步學習如何透過 AI 開發 Spring Framework 應用,讓 AI 協助理解框架、撰寫程式、除錯與驗>證,歡迎到 Hahow 看凱文大叔的最新課程【駕馭 AI 的全端實戰養成班:從零打造企業級智慧應用系統】。一起>學習如何駕馭 AI,提升 Spring 應用的開發效率與品質。
課程連結


上一篇
Day 08:用名字和標籤把流程說清楚
下一篇
Day 10:計畫趕不上變化時怎麼辦
系列文
讓 AI Agent 真的做事:用 Embabel 打造可控、可測試的智慧 Dashboard14
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言